package main

import (
	"bytes"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"net/url"
	"strings"
)

func rsa_encrypt_by_publick_key(pubkey *rsa.PublicKey, data []byte) ([]byte, error) {
	maxBlockSize := pubkey.Size() - 11
	if len(data) <= maxBlockSize {
		encryptData, err := rsa.EncryptPKCS1v15(rand.Reader, pubkey, data)
		return encryptData, err
	}

	var result []byte
	pos := 0
	for pos < len(data) {
		endPos := pos + maxBlockSize
		if endPos > len(data) {
			endPos = len(data)
		}
		dd := data[pos:endPos]
		encryptData, err := rsa.EncryptPKCS1v15(rand.Reader, pubkey, dd)
		if err != nil {
			return nil, err
		}
		result = append(result, encryptData...)

		pos += maxBlockSize
	}
	return result, nil
}

func rsa_decrypt_by_private_key(prikey *rsa.PrivateKey, data []byte) ([]byte, error) {
	maxBlockSize := prikey.Size()
	fmt.Printf("block size: %d\n", maxBlockSize)
	fmt.Printf("data size: %d\n", len(data))

	if len(data) <= maxBlockSize {
		decryptData, err := rsa.DecryptPKCS1v15(rand.Reader, prikey, data)
		return decryptData, err
	}

	var result []byte
	pos := 0
	for pos < len(data) {
		endPos := pos + maxBlockSize
		if endPos > len(data) {
			endPos = len(data)
		}
		dd := data[pos:endPos]
		decryptData, err := rsa.DecryptPKCS1v15(rand.Reader, prikey, dd)
		if err != nil {
			return nil, err
		}
		result = append(result, decryptData...)

		pos += maxBlockSize
	}
	return result, nil
}

//================================================================================
type TRsaSign struct {
	Src     string `json:"src" form:"src" binding:"required"`
	Format  string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64, plain 或者为空
	RsaType string `json:"rsa,omitempty" form:"rsa,omitempty" binding:"required"` // 可能的值：rsa1, rsa2
}

func rsa_sign(c *gin.Context) {
	input := &TRsaSign{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.Format) == 0 {
		input.Format = "plain"
	}

	var data []byte

	switch input.Format {
	case "hex":
		data, err = hex.DecodeString(input.Src)
		break
	case "base64":
		data, err = base64.StdEncoding.DecodeString(input.Src)
		break
	case "plain":
		data = []byte(input.Src)
		break
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.Format)
	}

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	var hashData []byte
	var hash crypto.Hash
	if input.RsaType == "rsa2" {
		hashed := sha256.Sum256(data)
		hashData = hashed[:]
		hash = crypto.SHA256
	} else {
		hashed := sha1.Sum(data)
		hashData = hashed[:]
		hash = crypto.SHA1
	}

	signature, err := rsa.SignPKCS1v15(rand.Reader, gRsaPrivKey, hash, hashData)

	if err != nil {
		Return_ok_result(c, "1000", "签名出错："+err.Error(), nil)
		return
	}

	v := &ReturnValue{
		Code:    "0000",
		Message: "",
		Format:  "base64",
	}
	v.Data = base64.StdEncoding.EncodeToString(signature)
	c.JSON(http.StatusOK, v)
}

//================================================================================
type TRsaVerify struct {
	SrcData    string `json:"src" form:"src" binding:"required"`
	SrcFormat  string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64, plain 或者为空
	RsaType    string `json:"rsa,omitempty" form:"rsa,omitempty" binding:"required"` // 可能的值：rsa1, rsa2
	SignBase64 string `json:"sign" form:"sign" binding:"required"`
}

func rsa_verify(c *gin.Context) {
	input := &TRsaVerify{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.SrcFormat) == 0 {
		input.SrcFormat = "plain"
	}

	var data []byte

	switch input.SrcFormat {
	case "hex":
		data, err = hex.DecodeString(input.SrcData)
		break
	case "base64":
		data, err = base64.StdEncoding.DecodeString(input.SrcData)
		break
	case "plain":
		data = []byte(input.SrcData)
		break
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.SrcFormat)
	}

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	sign, err := base64.StdEncoding.DecodeString(input.SignBase64)
	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	//bVerified := gHyRsaPubKey.Ver(data, sign) rsa.()
	//hashed := sha256.Sum256(data)
	var hashData []byte
	var hash crypto.Hash
	if input.RsaType == "rsa2" {
		hashed := sha256.Sum256(data)
		hashData = hashed[:]
		hash = crypto.SHA256
	} else {
		hashed := sha1.Sum(data)
		hashData = hashed[:]
		hash = crypto.SHA1
	}

	err = rsa.VerifyPKCS1v15(gHyRsaPubKey, hash, hashData, sign)

	bVerified := err == nil

	Return_sign_verification_result(c, bVerified)
}

//================================================================================
type TRsaEncrypt struct {
	Src    string `json:"src" form:"src" binding:"required"`
	Format string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64, plain 或者为空
}

func rsa_encrypt(c *gin.Context) {
	input := &TRsaEncrypt{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.Format) == 0 {
		input.Format = "plain"
	}

	var data []byte

	switch input.Format {
	case "hex":
		data, err = hex.DecodeString(input.Src)
		break
	case "base64":
		data, err = base64.StdEncoding.DecodeString(input.Src)
		break
	case "plain":
		data = []byte(input.Src)
		break
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.Format)
	}

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	encryptData, err := rsa_encrypt_by_publick_key(gHyRsaPubKey, data)

	if err != nil {
		Return_ok_result(c, "1000", "签名出错："+err.Error(), nil)
		return
	}

	v := &ReturnValue{
		Code:    "0000",
		Message: "",
		Format:  "base64",
	}
	v.Data = base64.StdEncoding.EncodeToString(encryptData)
	c.JSON(http.StatusOK, v)
}

//================================================================================
type TRsaDecrypt struct {
	EncryptData string `json:"enc" form:"enc" binding:"required"`
	Format      string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64 或者为空
}

func rsa_decrypt(c *gin.Context) {
	input := &TRsaDecrypt{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.Format) == 0 {
		input.Format = "plain"
	}

	var data []byte
	data, err = base64.StdEncoding.DecodeString(input.EncryptData)

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	decryptData, err := rsa_decrypt_by_private_key(gRsaPrivKey, data)

	if err != nil {
		Return_ok_result(c, "1000", "解密出错："+err.Error(), nil)
		return
	}

	var decryptDataFormatted string

	switch input.Format {
	case "hex":
		decryptDataFormatted = hex.EncodeToString(decryptData)
		break
	case "base64":
		decryptDataFormatted = base64.StdEncoding.EncodeToString(decryptData)
		break
	case "plain":
		decryptDataFormatted = string(decryptData)
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.Format)
	}

	v := &ReturnValue{
		Code:    "0000",
		Message: "",
		Format:  input.Format,
	}
	v.Data = decryptDataFormatted
	c.JSON(http.StatusOK, v)
}

//================================================================================
type TRsaEncryptAndSign struct {
	EncSrc      string `json:"enc_src" form:"enc_src" binding:"required"`
	SignContent string `json:"sign_content" form:"sign_content" binding:"required"`
	Format      string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64, plain 或者为空
	RsaType     string `json:"rsa,omitempty" form:"rsa,omitempty" binding:"required"` // 可能的值：rsa1, rsa2
}

func rsa_encrypt_sign(c *gin.Context) {
	input := &TRsaEncryptAndSign{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.Format) == 0 {
		input.Format = "plain"
	}

	var data []byte

	switch input.Format {
	case "hex":
		data, err = hex.DecodeString(input.EncSrc)
		break
	case "base64":
		data, err = base64.StdEncoding.DecodeString(input.EncSrc)
		break
	case "plain":
		data = []byte(input.EncSrc)
		break
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.Format)
	}

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	encryptData, err := rsa_encrypt_by_publick_key(gHyRsaPubKey, data)

	if err != nil {
		Return_ok_result(c, "1000", "签名出错："+err.Error(), nil)
		return
	}

	encryptDataBase64 := base64.StdEncoding.EncodeToString(encryptData)

	switch input.Format {
	case "hex":
		data, err = hex.DecodeString(input.SignContent)
		break
	case "base64":
		data, err = base64.StdEncoding.DecodeString(input.SignContent)
		break
	case "plain":
		data = []byte(input.SignContent)
		break
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.Format)
	}

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	sign_str := string(data)
	sign_str = strings.ReplaceAll(sign_str, "$(encrypt_content)", input.EncSrc)
	data = []byte(sign_str)

	var hashData []byte
	var hash crypto.Hash
	if input.RsaType == "rsa2" {
		hashed := sha256.Sum256(data)
		hashData = hashed[:]
		hash = crypto.SHA256
	} else {
		hashed := sha1.Sum(data)
		hashData = hashed[:]
		hash = crypto.SHA1
	}

	signature, err := rsa.SignPKCS1v15(rand.Reader, gRsaPrivKey, hash, hashData)

	if err != nil {
		fmt.Printf("hash data: %x\n", hashData)
		Return_ok_result(c, "1000", "签名出错："+err.Error(), nil)
		return
	}

	signBase64 := base64.StdEncoding.EncodeToString(signature)

	v := &ReturnValue{
		Code:    "0000",
		Message: "",
		Format:  "form",
	}
	v.Data = "encrypt_data=" + url.QueryEscape(encryptDataBase64) + "&sign=" + url.QueryEscape(signBase64)
	c.JSON(http.StatusOK, v)
}

//================================================================================
type TRsaDecryptAndVerify struct {
	EncryptData string `json:"enc" form:"enc" binding:"required"`
	SignContent string `json:"sign_content" form:"sign_content"`                      // 如果为空，默认为 $(encrypt_content)
	Format      string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64
	RsaType     string `json:"rsa,omitempty" form:"rsa,omitempty" binding:"required"` // 可能的值：rsa1, rsa2
	SignBase64  string `json:"sign" form:"sign" binding:"required"`
}

func rsa_decrypt_verify(c *gin.Context) {
	input := &TRsaDecryptAndVerify{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.Format) == 0 {
		input.Format = "plain"
	}

	var data []byte
	data, err = base64.StdEncoding.DecodeString(input.EncryptData)

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		fmt.Printf("base64 data: %s\n", input.EncryptData)
		return
	}

	decryptData, err := rsa_decrypt_by_private_key(gRsaPrivKey, data)

	if err != nil {
		Return_ok_result(c, "1001", "签名出错："+err.Error(), nil)
		return
	}

	//fmt.Printf("decryptData: %x\n", decryptData)

	var decryptDataFormatted string

	switch input.Format {
	case "hex":
		decryptDataFormatted = hex.EncodeToString(decryptData)
		break
	case "base64":
		decryptDataFormatted = base64.StdEncoding.EncodeToString(decryptData)
		break
	case "plain":
		decryptDataFormatted = string(decryptData)
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.Format)
	}
	//fmt.Printf("decryptDataFormatted: %s\n", decryptDataFormatted)

	if len(input.SignContent) == 0 {
		input.SignContent = "$(encrypt_content)"
	}

	sign_content := strings.ReplaceAll(input.SignContent, "$(encrypt_content)", string(decryptData))

	var hashData []byte
	var hash crypto.Hash
	if input.RsaType == "rsa2" {
		hashed := sha256.Sum256([]byte(sign_content))
		hashData = hashed[:]
		hash = crypto.SHA256
	} else {
		hashed := sha1.Sum([]byte(sign_content))
		hashData = hashed[:]
		hash = crypto.SHA1
	}

	sign, _ := base64.StdEncoding.DecodeString(input.SignBase64)
	err = rsa.VerifyPKCS1v15(gHyRsaPubKey, hash, hashData, sign)

	bVerified := err == nil
	if err != nil {
		//fmt.Printf("error1: %v\n", err)

		var out bytes.Buffer
		err = json.Indent(&out, decryptData, "", "  ")
		if err != nil {
			fmt.Printf("error: %v\n", err)
		}
		decryptDataStr := string(out.Bytes())
		if !strings.Contains(decryptDataStr, "\r") {
			decryptDataStr = strings.ReplaceAll(decryptDataStr, "\n", "\r\n")
		}
		sign_content = strings.ReplaceAll(input.SignContent, "$(encrypt_content)", decryptDataStr)
		//fmt.Printf("sign content formatted: %v\n", sign_content)
		if input.RsaType == "rsa2" {
			hashed := sha256.Sum256([]byte(sign_content))
			hashData = hashed[:]
		} else {
			hashed := sha1.Sum([]byte(sign_content))
			hashData = hashed[:]
		}
		err = rsa.VerifyPKCS1v15(gHyRsaPubKey, hash, hashData, sign)
		if err != nil {
			fmt.Printf("error2: %v\n", err)
		}
		bVerified = err == nil
	}

	v := &ReturnValue{
		Code:    "0000",
		Message: "验签成功",
		Format:  input.Format,
	}
	v.Data = decryptDataFormatted
	if !bVerified {
		fmt.Printf("验签失败，签名串为：%s\n", sign_content)

		v.Code = "0002"
		v.Message = "验签失败"
	}
	c.JSON(http.StatusOK, v)
}
